package com.hmall.search.controller;


import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmall.api.dto.ItemDTO;
import com.hmall.common.domain.PageDTO;
import com.hmall.search.domain.po.Item;
import com.hmall.search.domain.query.ItemPageQuery;
import com.hmall.search.domain.vo.SearchFiltersVO;
import com.hmall.search.service.ISearchService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Api(tags = "搜索相关接口")
@RestController
@RequestMapping("/search")
@RequiredArgsConstructor
public class SearchController {

    private final ISearchService searchService;

    private RestHighLevelClient client = new RestHighLevelClient(
            RestClient.builder(HttpHost.create("http://192.168.64.128:9200")));




    //暂停使用了
    public PageDTO<ItemDTO> searchByDB(ItemPageQuery query) {
        // 分页查询
        Page<Item> result = searchService.lambdaQuery()
                .like(StrUtil.isNotBlank(query.getKey()), Item::getName, query.getKey())
                .eq(StrUtil.isNotBlank(query.getBrand()), Item::getBrand, query.getBrand())
                .eq(StrUtil.isNotBlank(query.getCategory()), Item::getCategory, query.getCategory())
                .eq(Item::getStatus, 1)
                .between(query.getMaxPrice() != null, Item::getPrice, query.getMinPrice(), query.getMaxPrice())
                .page(query.toMpPage("update_time", false));
        // 封装并返回
        return PageDTO.of(result, ItemDTO.class);
    }




    @ApiOperation("搜索商品")
    @GetMapping("/list")
    public PageDTO<ItemDTO> search(ItemPageQuery query) throws IOException {
        //1.创建请求
        SearchRequest request = new SearchRequest("items");
        //2.准备资源
        configBasePageSource(request,query);
        //3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //4.解析结果
        PageDTO<ItemDTO> pageDTO = new PageDTO<>();
        List<ItemDTO> list = new ArrayList<>();

        SearchHits hits = response.getHits();
        long total = hits.getTotalHits().value;
        SearchHit[] hitsHits = hits.getHits();
        for(SearchHit searchHit : hitsHits){
            String json = searchHit.getSourceAsString();
            ItemDTO itemDTO = JSONUtil.toBean(json, ItemDTO.class);
            list.add(itemDTO);
        }
        pageDTO.setTotal(total);
        pageDTO.setPages((long) Math.ceil(total/query.getPageSize()));
        pageDTO.setList(list);
        return pageDTO;
    }


    @ApiOperation("过滤条件")
    @PostMapping("/filters")
    public SearchFiltersVO filter(@RequestBody ItemPageQuery query) throws IOException {
        //1.创建请求
        SearchRequest request = new SearchRequest("items");
        //2.准备资源
        configBasePageSource(request,query);
        request.source().aggregation(AggregationBuilders.terms("brand_agg").field("brand"));
        request.source().aggregation(AggregationBuilders.terms("category_agg").field("category"));
        //3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //4.解析结果
        List<String> brand = new ArrayList<>();
        List<String> category = new ArrayList<>();

        Terms brand_agg = response.getAggregations().get("brand_agg");
        List<? extends Terms.Bucket> buckets = brand_agg.getBuckets();
        for(Terms.Bucket bucket:buckets){
            String key = bucket.getKeyAsString();
            brand.add(key);
        }
        Terms category_agg = response.getAggregations().get("category_agg");
        List<? extends Terms.Bucket> buckets1 = category_agg.getBuckets();
        for(Terms.Bucket bucket:buckets1){
            String key = bucket.getKeyAsString();
            category.add(key);
        }
        //5.返回对象
        SearchFiltersVO searchFiltersVO = SearchFiltersVO.builder()
                .category(category)
                .brand(brand)
                .build();

        return searchFiltersVO;
    }



    public void configBasePageSource(SearchRequest request,ItemPageQuery query){
        //bool复合查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(StrUtil.isNotBlank(query.getKey())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("name",query.getKey()));
        }
        if(StrUtil.isNotBlank(query.getBrand())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("barnd",query.getBrand()));
        }
        if(StrUtil.isNotBlank(query.getCategory())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("category",query.getCategory()));
        }
        if(query.getMaxPrice()!=null){
            boolQueryBuilder.filter(
                    QueryBuilders
                            .rangeQuery("price")
                            .gte(query.getMinPrice())
                            .lte(query.getMaxPrice()));
        }
        //分页
        request.source()
                .query(boolQueryBuilder)
                .size(query.getPageSize())
                .from((query.getPageNo()-1)*query.getPageSize());
        //排序
        if(StrUtil.isNotBlank(query.getSortBy())){
            request.source().sort(query.getSortBy(),query.getIsAsc() ? SortOrder.ASC:SortOrder.DESC);
        }else {
            request.source().sort("updateTime",query.getIsAsc() ? SortOrder.ASC:SortOrder.DESC);
        }

    }
}
